﻿using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TaskManageDemo.Core;
using TaskManageDemo.Data;
using TaskManageDemo.Data.Entitys;
using TaskManageDemo.Utility;

namespace TaskManageDemo.Task
{
    /// <summary>
    /// 系统作业
    /// 通过系统作业来唤醒其他作业
    /// </summary>
    public class SysJob : JobBase
    {
        private readonly IRepository _scheduleTask;
        public SysJob()
        {
            this._scheduleTask = new Repository();
        }
        protected override void ExecuteJobImpl(Quartz.IJobExecutionContext context)
        {
            //取所有运行的作业
            Quartz.Collection.ISet<JobKey> jobKeys = context.Scheduler.GetJobKeys(
                   Quartz.Impl.Matchers.GroupMatcher<JobKey>.GroupEquals(JobHelp.jobGroupName));

            string sql = "select * from ScheduleTask where ClassName!=@ClassName";
            var taskRuning = new List<ScheduleTask>();//正在运行的作业
            var taskInDb = _scheduleTask.Query<ScheduleTask>(sql, new { ClassName = "SysJob" }); //存在于数据库的作业，不包括系统作业
            foreach (var jk in jobKeys)
            {
                IJobDetail job = context.Scheduler.GetJobDetail(jk);
                ScheduleTask task = job.JobDataMap["task"] as ScheduleTask;
                if (task == null || task.ClassName == "SysJob") continue;  //不检查系统作业  

                //在数据库检测一次
                var taskInDb2 = taskInDb.ToList().FirstOrDefault(a => a.Id == task.Id);
                if (taskInDb2 == null)
                {
                    context.Scheduler.DeleteJob(jk); //删除该作业
                    Log.Logger.InfoFormat("作业计划『{0}』已经不存在于数据库。", task.ClassName);
                    continue;
                }
                taskRuning.Add(taskInDb2);

                if (taskInDb2 != task)
                {

                    //脏数据，删除此作业，然后重新创建一个
                    Log.Logger.InfoFormat("{0}的作业计划属性已更改，将删除该计划的实现作业，然后重新创建一个作业，并尝试调度它...", taskInDb2.ClassName);
                    //作业计划属性发生变更，重新启动作业
                    Tuple<IJobDetail, ITrigger> tuple = JobHelp.RestartJob(context.Scheduler, task, taskInDb2);
                    Log.Logger.InfoFormat("{0}重新创建并调度作业完成，『IJOB.Execute』退出。作业计划：{1}，作业：{2}，触发器：{3}，表达式：{4}。", taskInDb2.ClassName, taskInDb2.ClassName, tuple.Item1.Key.Name, tuple.Item2.Key.Name, taskInDb2.CronExpression);
                    return; //退出
                }
            }
            //过滤出新增的作业
            var newTask = taskInDb.Except(taskRuning);
            if (newTask.Count() > 0)
            {
                //动态增加作业
                Log.Logger.InfoFormat("系统作业检测到有{0}个新增作业计划，开始创建这些作业...", newTask.Count());
                foreach (var task in newTask)
                    TaskManageDemo.Utility.Common.Execute(ScheduleJobByPlan, context.Scheduler, task, "创建作业失败，作业计划名称：{0}", task.ClassName); //作业计划各个属性为合法，使用此作业计划初始化采集作业 

                Log.Logger.InfoFormat("系统作业创建作业完毕，共创建{0}个作业。", context.Scheduler.GetJobKeys(Quartz.Impl.Matchers.GroupMatcher<JobKey>.GroupEquals(JobHelp.jobGroupName)).Count - 1);
            }
            //系统作业执行完毕
            Log.Logger.InfoFormat("系统轮询作业执行完毕，目前共{0}个作业正在运行。", context.Scheduler.GetJobKeys(Quartz.Impl.Matchers.GroupMatcher<JobKey>.GroupEquals(JobHelp.jobGroupName)).Count);
            context.Put("ExecResult", "系统作业执行完成。");

            //Log.Logger.ErrorFormat("本次运行时间{0},下次运行时间{1}", DateTime.Now.ToString(), context.NextFireTimeUtc.Value.DateTime.AddHours(8).ToString());
        }


        #region 辅助方法

        //使用作业计划来创建作业
        private void ScheduleJobByPlan(IScheduler qtzScheduler, ScheduleTask task)
        {

            Tuple<IJobDetail, ITrigger> tuple = TaskManageDemo.Core.JobHelp.ScheduleJobByPlan(qtzScheduler, task);
            Log.Logger.InfoFormat("系统作业新增作业成功，作业计划：{0}，作业：{1}，触发器：{2}，表达式：{3}。", task.ClassName, tuple.Item1.Key.Name, tuple.Item2.Key.Name, task.CronExpression);
           
        }

        #endregion
    }
}
